﻿using System;
using System.Linq;
using System.Threading.Tasks;
using IdentityModel;
using K9Nano.Admin.Settings;
using K9Nano.Admin.Weixin.Dto;
using K9Nano.Admin.Weixin.OAuth;
using K9Nano.AspNetCore.Api;
using K9Nano.Runtime;
using K9Nano.Security;
using K9Nano.Share;
using K9Nano.Share.Exceptions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Push.Remoting;

namespace K9Nano.Admin.Weixin
{
    //[AllowAnonymous]
    [Route("weixin/[action]")]
    [ApiExplorerSettings(IgnoreApi = true)]
    public class WeixinController : Controller
    {
        protected readonly IWeixinAppService WeixinAppService;
        protected readonly VerificationService.VerificationServiceClient VerificationService;
        protected readonly IUrlSignManager UrlSignManager;
        protected readonly IWeixinTokenCodeCache WeixinTokenCodeCache;
        protected readonly ILogger Logger;

        public WeixinController(IWeixinAppService weixinAppService,
            VerificationService.VerificationServiceClient verificationService,
            IUrlSignManager urlSignManager,
            IWeixinTokenCodeCache weixinTokenCodeCache,
            ILoggerFactory loggerFactory)
        {
            WeixinAppService = weixinAppService;
            VerificationService = verificationService;
            UrlSignManager = urlSignManager;
            WeixinTokenCodeCache = weixinTokenCodeCache;
            Logger = loggerFactory.CreateLogger(this.GetType());
        }

        [Authorize(AuthenticationSchemes = WeixinDefaults.AuthenticationScheme)]
        [HttpGet]
        public virtual async Task<IActionResult> Authorize(string clientId, string returnUrl)
        {
            if (string.IsNullOrEmpty(clientId))
            {
                throw new K9UserFriendlyException("clientId 不能为空");
            }

            if (string.IsNullOrEmpty(returnUrl))
            {
                throw new K9UserFriendlyException("returnUrl 不能为空");
            }

            if (!Uri.IsWellFormedUriString(returnUrl, UriKind.Absolute))
            {
                throw new K9UserFriendlyException("returnUrl 不合法: " + returnUrl);
            }

            var openId = User.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject)?.Value;
            var profile = User.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Profile)?.Value;
            var unionId = User.Claims.FirstOrDefault(x => x.Type == "urn:wechat:unionid")?.Value;
            var appId = User.Claims.FirstOrDefault(x => x.Type == "urn:wechat:appid")?.Value;
            // 是否已经绑定

            if (await WeixinAppService.IsBoundAsync(clientId, appId, openId, unionId, HttpContext.RequestAborted))
            {
                return ReturnTokenCode(new WeixinTokenCode
                {
                    ClientId = clientId,
                    AppId = appId,
                    OpenId = openId,
                    UnionId = unionId
                }, returnUrl);
            }

            // TODO 校验sign

            // 未绑定
            return RedirectToAction(nameof(Bind), new WeixinMpBindModel
            {
                ClientId = clientId,
                AppId = appId,
                OpenId = openId,
                UnionId = unionId,
                ReturnUrl = returnUrl,
                Profile = profile,
                Sign = "sign"
            });
        }

        [HttpGet]
        public virtual async Task<IActionResult> Login([FromQuery] WeixinMpLoginModel model)
        {
            if (!await WeixinAppService.ValidateRedirectUrlAsync(model.ClientId, model.ReturnUrl))
            {
                throw new K9UserFriendlyException("回调地址非法");
            }

            // TODO 校验sign
            var ticket = await WeixinAppService.WeixinAuthenticateAsync(model, HttpContext.RequestAborted);
            if (ticket == null)
            {
                // 未找到绑定的用户，转到绑定界面
                return RedirectToAction(nameof(Bind), model);
            }

            return await SignInInternalAsync(ticket, model.ReturnUrl);
        }

        [HttpGet]
        public virtual async Task<IActionResult> Bind([FromQuery] WeixinMpLoginModel model,
            [FromServices] IOptions<PushOptions> options,
            [FromServices] IAdminSettingsAppService adminSettingsAppService)
        {
            //if (!await WeixinAppService.ValidateRedirectUrlAsync(model.ClientId, model.ReturnUrl))
            //{
            //     throw new K9UserFriendlyException("回调地址非法");
            //}

            ViewBag.SmsHost = options.Value.Host;

            ViewBag.Sms = await adminSettingsAppService.GetSmsVerificationSettingsAsync(HttpContext.RequestAborted);

            // TODO 校验sign
            return View(new WeixinMpBindModel(model));
        }

        [HttpPost]
        public virtual async Task<IActionResult> Bind([FromForm] WeixinMpBindModel model)
        {
            if (!await WeixinAppService.ValidateRedirectUrlAsync(model.ClientId, model.ReturnUrl))
            {
                throw new K9UserFriendlyException("回调地址非法");
            }

            var reply = VerificationService.Verify(new VerifyRequest
            {
                Id = model.MessageId,
                Code = model.Code,
                Recipient = model.Phone
            });

            if (!reply.Success)
            {
                throw new K9UserFriendlyException("验证码错误");
            }

            await WeixinAppService.WeixinMpBindAsync(model, HttpContext.RequestAborted);

            // Get Token
            return ReturnTokenCode(new WeixinTokenCode
            {
                ClientId =  model.ClientId,
                AppId = model.AppId,
                OpenId = model.OpenId,
                UnionId = model.UnionId
            }, model.ReturnUrl);
        }

        [Authorize]
        [HttpPost]
        public virtual async Task<ApiResponse> Unbind([FromServices] ISessionContext sessionContext)
        {
            try
            {
                var model = new WeixinMpUnbindModel
                {
                    ClientId = sessionContext.ClientId,
                    UserId = sessionContext.RequiredUserId.ToString()
                };
                await WeixinAppService.WeixinUnbindAsync(model, HttpContext.RequestAborted);
                return new ApiResponse();
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "解除绑定失败：" + sessionContext.RequiredUserId);
                return new ApiResponse(500, "解除绑定失败", "内部错误");
            }

        }

        protected virtual async Task<IActionResult> SignInInternalAsync(AuthenticationTicket ticket, string returnUrl)
        {
            await HttpContext.SignInAsync("Cookies", ticket.Principal, ticket.Properties);

            return Redirect(returnUrl);
        }

        protected virtual IActionResult ReturnTokenCode(WeixinTokenCode tokenCode, string returnUrl)
        {
            // Get Token
            try
            {
                var code = WeixinTokenCodeCache.CreateCode(tokenCode);
                var uri = new Uri(returnUrl);
                var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query)
                    .ToDictionary(x => x.Key, x => x.Value.ToString());
                query.Add("code", code);
                var host = QueryHelpers.GetHostAndPath(uri);
                var redirectUrl = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(host, query);
                return Redirect(redirectUrl);
            }
            catch (Exception ex)
            {
                throw new K9UserFriendlyException(400, "回调地址非法：" + returnUrl, ex);
            }
        }
    }
}